feat(control): add extension sideloading#2547
Conversation
Greptile SummaryThis PR adds a public
Confidence Score: 5/5Safe to merge; the core registration and lookup paths are correct, well-tested, and backward-compatible. The extension facade, shared normalization utilities, and duplicate-rejection logic are all straightforward and covered by thorough unit and integration tests. No existing callers are broken. The two findings are both in non-production example/utility code and do not affect coordinator correctness. dimos/control/tasks/registry_utils.py (whitespace validation gap) and examples/external_control_extension/dimos_external_control_extension/blueprints.py (redundant register_extensions call). Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Ext as External Package
participant Facade as dimos.control.extensions
participant HWReg as Hardware Registry
participant TaskReg as ControlTaskRegistry
participant Coord as ControlCoordinator
Note over Ext: Module import time
Ext->>Facade: register_hardware_adapter(BASE, name, factory)
Facade->>Facade: normalize_adapter_name(name)
Facade->>HWReg: register(key, factory)
HWReg-->>Facade: OK (idempotent if same factory)
Ext->>Facade: register_control_task(type, module:attr)
Facade->>Facade: normalize_task_name / validate_factory_path
Facade->>TaskReg: register_path(key, factory_path)
TaskReg-->>Facade: OK
Note over Ext: Coordinator construction
Ext->>Coord: ControlCoordinator(hardware, tasks)
Note over Coord: coordinator.start()
Coord->>HWReg: create(adapter_type)
HWReg-->>Coord: adapter instance
Coord->>TaskReg: create(task_type, cfg, hardware)
TaskReg->>TaskReg: importlib.import_module(module)
TaskReg-->>Coord: task instance
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Ext as External Package
participant Facade as dimos.control.extensions
participant HWReg as Hardware Registry
participant TaskReg as ControlTaskRegistry
participant Coord as ControlCoordinator
Note over Ext: Module import time
Ext->>Facade: register_hardware_adapter(BASE, name, factory)
Facade->>Facade: normalize_adapter_name(name)
Facade->>HWReg: register(key, factory)
HWReg-->>Facade: OK (idempotent if same factory)
Ext->>Facade: register_control_task(type, module:attr)
Facade->>Facade: normalize_task_name / validate_factory_path
Facade->>TaskReg: register_path(key, factory_path)
TaskReg-->>Facade: OK
Note over Ext: Coordinator construction
Ext->>Coord: ControlCoordinator(hardware, tasks)
Note over Coord: coordinator.start()
Coord->>HWReg: create(adapter_type)
HWReg-->>Coord: adapter instance
Coord->>TaskReg: create(task_type, cfg, hardware)
TaskReg->>TaskReg: importlib.import_module(module)
TaskReg-->>Coord: task instance
Reviews (3): Last reviewed commit: "Apply suggestions from code review" | Re-trigger Greptile |
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## main #2547 +/- ##
==========================================
- Coverage 70.79% 70.48% -0.32%
==========================================
Files 862 876 +14
Lines 77504 77963 +459
Branches 6886 6926 +40
==========================================
+ Hits 54872 54951 +79
- Misses 20843 21233 +390
+ Partials 1789 1779 -10
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 28 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Co-authored-by: cc <55869557+TomCC7@users.noreply.github.com>
Problem
External robot packages need a supported way to register ControlCoordinator hardware adapter names and control task types without placing files inside the DimOS source tree. Without this, an outside package can define a blueprint but still cannot use
HardwareComponent(adapter_type=...)orTaskConfig(type=...)for custom hardware/control unless DimOS itself is modified.Closes DIM-1031
Solution
Add a public
dimos.control.extensionsfacade for explicit extension registration:register_hardware_adapter(HardwareType, adapter_type, factory)dispatches to the existing manipulator, base, or whole-body adapter registry.register_control_task(task_type, factory_path)registers lazy control task factories without importing the target module at registration time.This keeps blueprint usage unchanged: external packages register before coordinator construction, then use normal
HardwareComponentandTaskConfignames.How to Test
Manual QA:
Expected output includes
[external_test_robot]logs for:BASE/external_test_baseexternal_test_driveExternalTestBaseAdapterExternalTestDriveTaskContributor License Agreement